﻿using ERPJopi.DAL.Entities;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic;
using System.Text;
using System.Threading.Tasks;

namespace ERPJopi.DAL.Model
{
    public class UsuarioModel : Interfaces.IUsuarioModel
    {
        /// <summary>
        /// Retorna Lista de Usuários com paginação sem uso de filtro
        /// </summary>
        /// <param name="qtdPorPagina">Quantidade de registros por página</param>
        /// <param name="paginaAtual">Página atual</param>
        /// <param name="campoOrdem">Nome do campo para ordenação</param>
        /// <returns>Lista de Usuários</returns>
        public Dictionary<ObjetoRetornoLista, List<DAL.Entities.Usuario>> Listar(int qtdPorPagina, int paginaAtual, string campoOrdem)
        {
            return ListarFiltro(qtdPorPagina, paginaAtual, "", null, campoOrdem);            
        }

        /// <summary>
        /// Retorna Lista de Usuários com paginação com uso de filtro
        /// </summary>
        /// <param name="qtdPorPagina">Quantidade de registros por página</param>
        /// <param name="paginaAtual">Página atual</param>
        /// <param name="filtro">Filtro que será usado na consulta. Usar @0 ... @3 para definir valores de parâmetros.</param>
        /// <param name="parametros">Lista do tipo object referente aos valores dos parâmetros obedecendo a ordem.</param>
        /// <param name="campoOrdem">Nome do campo para ordenação</param>
        /// <returns>Lista de Usuários</returns>
        public Dictionary<ObjetoRetornoLista, List<Usuario>> ListarFiltro(int qtdPorPagina, int paginaAtual, string filtro, object[] parametros, string campoOrdem)
        {
            Context.Contexto contexto = new Context.Contexto();

            int totRegistros = 0, totPaginas = 0, registroInicial = 0;

            List<DAL.Entities.Usuario> lista = new List<DAL.Entities.Usuario>();

            Dictionary<ObjetoRetornoLista, List<DAL.Entities.Usuario>> retorno =
                new Dictionary<ObjetoRetornoLista, List<DAL.Entities.Usuario>>();

            try
            {
                totRegistros =
                    filtro.Trim() == string.Empty
                    ? contexto.Usuario.AsQueryable().Where(filtro, parametros).Where(o => o.Status != DAL.Enums.StatusPessoa.Excluido).Count()
                    : contexto.Usuario.AsQueryable().Where(o => o.Status != DAL.Enums.StatusPessoa.Excluido).Count();
                totPaginas = totRegistros / qtdPorPagina + ((totRegistros % qtdPorPagina) > 0 ? 1 : 0);
                registroInicial = (paginaAtual - 1) * qtdPorPagina;
                lista =
                        campoOrdem.Trim() != ""
                        ? (
                            filtro.Trim() != string.Empty
                            ? contexto.Usuario.AsQueryable().Where(filtro, parametros).Where(o => o.Status != DAL.Enums.StatusPessoa.Excluido).OrderBy(campoOrdem).Skip(registroInicial).Take(qtdPorPagina).ToList()
                            : contexto.Usuario.AsQueryable().Where(o => o.Status != DAL.Enums.StatusPessoa.Excluido).OrderBy(campoOrdem).Skip(registroInicial).Take(qtdPorPagina).ToList()
                          )
                        : (
                            filtro.Trim() != string.Empty
                            ? contexto.Usuario.AsQueryable().Where(filtro, parametros).Where(o => o.Status != DAL.Enums.StatusPessoa.Excluido).OrderBy(o => o.Nome).Skip(registroInicial).Take(qtdPorPagina).ToList()
                            : contexto.Usuario.AsQueryable().Where(o => o.Status != DAL.Enums.StatusPessoa.Excluido).OrderBy(o => o.Nome).Skip(registroInicial).Take(qtdPorPagina).ToList()
                          );
            }
            catch (Exception ex)
            {
                ObjetoRetornoLista objRetErro =
                new ObjetoRetornoLista
                {
                    Mensagem = ex.Message,
                    PagAtual = paginaAtual,
                    QtdPorPagina = qtdPorPagina,
                    QtdRegistros = totRegistros,
                    Sucesso = false,
                    TotalPaginas = totPaginas
                };
                retorno.Add(objRetErro, lista);
                return retorno;
            }

            ObjetoRetornoLista objRet =
                new ObjetoRetornoLista
                {
                    Mensagem = "Sucesso",
                    PagAtual = paginaAtual,
                    QtdPorPagina = qtdPorPagina,
                    QtdRegistros = totRegistros,
                    Sucesso = true,
                    TotalPaginas = totPaginas
                };
            retorno.Add(objRet, lista);

            return retorno;
        }

        /// <summary>
        /// Incluir Usuário
        /// </summary>
        /// <param name="usuario">Usuário</param>
        /// <returns>Usuário gravado</returns>
        public Dictionary<ObjetoRetorno, Usuario> Incluir(Usuario usuario)
        {
            // Verificando se o Usuário já existe
            Context.Contexto contexto = new Context.Contexto();
            if (contexto.Usuario.Any(o => o.Login == usuario.Login || o.IdUsuario == usuario.IdUsuario))
                return new Dictionary<ObjetoRetorno, Usuario>() { { 
                    new ObjetoRetorno{ Sucesso=false, Mensagem= "Já existe", QtdRegistros=0 }, 
                    usuario } };
            else
            {
                // Tentar fazer a inclusão
                contexto.Usuario.Add(usuario);

                

                try
                {
                    int qtdRetorno = contexto.SaveChanges();
                    return new Dictionary<ObjetoRetorno, Usuario>() { { 
                        new ObjetoRetorno { Sucesso = true, Mensagem = "Gravado com sucesso!!!", QtdRegistros = qtdRetorno }, 
                        usuario } };
                }
                catch (Exception ex)
                {
                    return new Dictionary<ObjetoRetorno, Usuario>() { { 
                        new ObjetoRetorno { Sucesso = false, Mensagem = ex.Message, QtdRegistros = 0 }, 
                        usuario } };
                }
            }
        }

        /// <summary>
        /// Alterar dados do Usuário
        /// </summary>
        /// <param name="usuario">Usuário</param>
        /// <returns>Usuário gravado</returns>
        public Dictionary<ObjetoRetorno, Usuario> Alterar(Usuario usuario)
        {
            // Verificando se o Usuário já existe
            Context.Contexto contexto = new Context.Contexto();
            Usuario usr = new Usuario();
            if (contexto.Usuario.Any(o => o.Login == usuario.Login || o.IdUsuario == usuario.IdUsuario))
            {
                try
                {                    
                    usr = contexto.Usuario.Single(o => o.IdUsuario == usuario.IdUsuario);
                    AutoMapper.Mapper.CreateMap<Usuario, Usuario>();
                    AutoMapper.Mapper.CreateMap<UsuarioEndereco, UsuarioEndereco>();
                    AutoMapper.Mapper.Map(usuario, usr);
                    
                    // Verificando os endereços
                    foreach (UsuarioEndereco endereco in usuario.UsuarioEnderecos)
                    {
                        // Incluindo ou alterando
                        if (usr.UsuarioEnderecos.Any(o => o.IdUsuarioEndereco == endereco.IdUsuarioEndereco))
                        {
                            UsuarioEndereco end = usr.UsuarioEnderecos.First(o => o.IdUsuarioEndereco == endereco.IdUsuarioEndereco);
                            AutoMapper.Mapper.Map(endereco, end);
                        }
                        else
                        {
                            usr.UsuarioEnderecos.Add(endereco);
                        }

                        // Excluindo
                        if (!usr.UsuarioEnderecos.Any(o => o.IdUsuarioEndereco == endereco.IdUsuarioEndereco))
                        {
                            usr.UsuarioEnderecos.RemoveAll(o => o.IdUsuarioEndereco == endereco.IdUsuarioEndereco);
                        }
                    }

                    // Verificando os telefones
                    foreach (UsuarioTelefone telefone in usuario.UsuarioTelefones)
                    {
                        // Incluindo ou alterando
                        if (usr.UsuarioTelefones.Any(o => o.IdUsuarioTelefone == telefone.IdUsuarioTelefone))
                        {
                            UsuarioTelefone tel = usr.UsuarioTelefones.First(o => o.IdUsuarioTelefone == telefone.IdUsuarioTelefone);
                            AutoMapper.Mapper.Map(telefone, tel);
                        }
                        else
                        {
                            usr.UsuarioTelefones.Add(telefone);
                        }

                        // Excluindo
                        if (!usr.UsuarioTelefones.Any(o => o.IdUsuarioTelefone == telefone.IdUsuarioTelefone))
                        {
                            usr.UsuarioTelefones.RemoveAll(o => o.IdUsuarioTelefone == telefone.IdUsuarioTelefone);
                        }
                    } 
                   
                    // Verificando perfis
                    foreach (UsuarioPerfil perfil in usuario.UsuarioPerfils)
                    {
                        // Incluindo ou alterando
                        if (usr.UsuarioPerfils.Any(o => o.IdUsuarioPerfil == perfil.IdUsuarioPerfil))
                        {
                            UsuarioPerfil tel = usr.UsuarioPerfils.First(o => o.IdUsuarioPerfil == perfil.IdUsuarioPerfil);
                            AutoMapper.Mapper.Map(perfil, tel);
                        }
                        else
                        {
                            usr.UsuarioPerfils.Add(perfil);
                        }

                        // Excluindo
                        if (!usr.UsuarioPerfils.Any(o => o.IdUsuarioPerfil == perfil.IdUsuarioPerfil))
                        {
                            usr.UsuarioPerfils.RemoveAll(o => o.IdUsuarioPerfil == perfil.IdUsuarioPerfil);
                        }
                    }

                    int qtd = contexto.SaveChanges();

                    return new Dictionary<ObjetoRetorno, Usuario> {{
                        new ObjetoRetorno { Mensagem = "Gravado com sucesso", QtdRegistros = qtd, Sucesso = true},
                        usr}};
                }
                catch (Exception ex)
                {
                    return new Dictionary<ObjetoRetorno, Usuario> {{
                        new ObjetoRetorno { Mensagem = ex.Message, QtdRegistros = 0, Sucesso = false},
                        usr}};
                }
            }
            else
            {
                return new Dictionary<ObjetoRetorno, Usuario> {{
                        new ObjetoRetorno { Mensagem = "Usuário não encontrado!!!", QtdRegistros = 0, Sucesso = true},
                        usr}};
            }
                
        }

        /// <summary>
        /// Excluir logicamente o Usuário
        /// </summary>
        /// <param name="usuario">Usuário</param>
        /// <returns>Resultado da exclusão</returns>
        public ObjetoRetorno Excluir(Usuario usuario)
        {
            //usuario.Status = Enums.StatusPessoa.Excluido;
            //this.Alterar(usuario);

            // Verificando se o Usuário já existe
            Context.Contexto contexto = new Context.Contexto();
            Usuario usr = new Usuario();
            if (contexto.Usuario.Any(o => o.Login == usuario.Login || o.IdUsuario == usuario.IdUsuario))
            {
                try
                {
                    usr = contexto.Usuario.Single(o => o.IdUsuario == usuario.IdUsuario);
                    usr.Status = Enums.StatusPessoa.Excluido;
                    int qtd = contexto.SaveChanges();
                    return new ObjetoRetorno { Mensagem = "Excluído com sucesso", QtdRegistros = qtd, Sucesso = true };
                }
                catch (Exception ex)
                {
                    return new ObjetoRetorno { Mensagem = ex.Message, QtdRegistros = 0, Sucesso = false };
                }
            }
            else
            {
                return new ObjetoRetorno { Mensagem = "Usuário não encontrado!!!", QtdRegistros = 0, Sucesso = true };
            }
        }

        /// <summary>
        /// Localizar usuário pelo codigo
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public Dictionary<ObjetoRetorno, Usuario> Localizar(string filtro, params object[] parametros)
        {
            // Verificando se o Usuário já existe
            Context.Contexto contexto = new Context.Contexto();
            Usuario usuario = new Usuario();
            ObjetoRetorno or = new ObjetoRetorno();
            try
            {
                usuario = contexto.Usuario.Include("UsuarioEndereco").Include("UsuarioTefone").Include("UsuarioTelefone").Where(filtro, parametros).FirstOrDefault();                
                or = new ObjetoRetorno { Mensagem = "Sucesso", QtdRegistros = 1, Sucesso = true };                
            }
            catch (Exception ex)
            {
                 or = new ObjetoRetorno { Mensagem = ex.Message, QtdRegistros = 01, Sucesso = false };
            }

            return new Dictionary<ObjetoRetorno, Usuario> { { or, usuario } };
           
        }
    }
}
